﻿/*
 * Description: Photoshop Process control, use dll to Preload
 */
#include <Windows.h>
#include <string>
#include "commctrl.h"
#pragma comment(lib, "Comctl32.lib")
namespace {
static LONG_PTR OldWndProc = NULL;  // 获取原来的窗口处理过程并保存下来，留待以后恢复用
#define WM_UNSUBCLASS (WM_USER + 1001)
#define HideId (0x2727)
static const std::wstring PS_WND_TEXT = L"Adobe Photoshop 2020";
static const int RETURN_TRUE = 1;

LRESULT CALLBACK HideProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
    if (hWnd == nullptr) {
        return DefSubclassProc(hWnd, uMsg, wParam, lParam);
    }
    if (uMsg != WM_UNSUBCLASS && reinterpret_cast<void *>(lParam) == nullptr) {
        return DefSubclassProc(hWnd, uMsg, wParam, lParam);
    }
    if (uMsg == WM_UNSUBCLASS) {
        BOOL ret = RemoveWindowSubclass(hWnd, HideProc, HideId);
        if (ret == FALSE) {
            PostMessage(hWnd, WM_CLOSE, 0, 0);
        }
    } else if (uMsg == WM_SHOWWINDOW) {
        wParam = FALSE;
    } else if (uMsg == WM_CREATE) {
        CREATESTRUCTA *info = reinterpret_cast<CREATESTRUCTA *>(lParam);
        info->style &= ~(WS_VISIBLE);
    } else if (uMsg == WM_STYLECHANGING) {
        STYLESTRUCT *info = reinterpret_cast<STYLESTRUCT *>(lParam);
        if (wParam == GWL_STYLE) {
            info->styleNew &= ~(WS_VISIBLE);
        }
    } else if (uMsg == WM_WINDOWPOSCHANGING) {
        WINDOWPOS *info = reinterpret_cast<WINDOWPOS *>(lParam);
        info->flags |= SWP_HIDEWINDOW;
        info->flags &= ~SWP_SHOWWINDOW;
    }
    return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}

bool MessageMatch(CWPSTRUCT *pCwp)
{
    if (pCwp->message == WM_SHOWWINDOW) {
        return true;
    }
    if (pCwp->message == WM_CREATE) {
        return true;
    }
    if (pCwp->message == WM_WINDOWPOSCHANGED) {
        return true;
    }
    if (pCwp->message == WM_WINDOWPOSCHANGING) {
        return true;
    }
    if (pCwp->message == WM_STYLECHANGED) {
        return true;
    }
    if (pCwp->message == WM_STYLECHANGING) {
        return true;
    }
    return false;
}

static HHOOK g_hHook = NULL;
extern "C" __declspec(dllexport) LRESULT CALLBACK WndHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (lParam == NULL) {
        return CallNextHookEx(g_hHook, nCode, wParam, lParam);
    }
    CWPSTRUCT *pCwp = reinterpret_cast<CWPSTRUCT *>(lParam);
    if (MessageMatch(pCwp)) {
        HWND hd = pCwp->hwnd;
        if (hd == nullptr) {
            return CallNextHookEx(g_hHook, nCode, wParam, lParam);
        }
        TCHAR pszMem[MAX_PATH];
        SecureZeroMemory(pszMem, MAX_PATH * sizeof(TCHAR));
        GetWindowText(hd, pszMem, MAX_PATH);
        std::wstring crtWndText = pszMem;
        if (crtWndText != PS_WND_TEXT) {
            return CallNextHookEx(g_hHook, nCode, wParam, lParam);
        }
        // 实现了窗口过程的重定向，以后每次PS有消息要处理，都必须得先经过我们自己实现的NewWndProc才行
        if (OldWndProc == NULL) {
            OldWndProc = GetWindowLongPtr(hd, GWLP_WNDPROC);
            if (OldWndProc != NULL) {
                SetWindowSubclass(hd, HideProc, HideId, 0);
            }
        }
    }
    return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
extern "C" __declspec(dllexport) int HookWndProc(HINSTANCE hmod, DWORD dwThreadId)
{
    g_hHook = SetWindowsHookEx(WH_CALLWNDPROC,
        (HOOKPROC)WndHookProc,
        hmod,
        dwThreadId);  // 安装一个挂钩过程，用于在系统将消息发送到目标窗口过程之前监视消息
    if (g_hHook == NULL) {
        return 0;
    }
    return RETURN_TRUE;
}

extern "C" __declspec(dllexport) BOOL UnHookWndProc(void)
{
    if (g_hHook == NULL) {
        return FALSE;
    }
    BOOL isUnHook = UnhookWindowsHookEx(g_hHook);
    g_hHook = NULL;
    return isUnHook;  // 删除 SetWindowsHookEx 函数安装在挂钩链中的挂钩过程。
}
}  // namespace